
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using Swaf;
using Swaf.BizObj;
using Swaf.Call;
using Swaf.Container;

namespace Swaf.Logging
{
    /// <summary>
    /// Summary description for Audit.
    /// </summary>
    public class Audit : BaseLog, IAudit
    {
        public Audit(string groupName)
            : base(groupName)
        {
            //
            // TODO: Add constructor logic here
            //
        }
        #region IAudit Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        public void write(INameAddressSupport map)
        {
            IBizObj auditInfo = null;
            if (map is IBizObj && ((IBizObj)map).type.Name == "AuditInfo")
            {
                // Take the audit info and assume it is as populated as necessary
                auditInfo = map as IBizObj;
                if (!auditInfo.isFieldSet("id"))
                {
                    auditInfo.put("id", Guid.NewGuid().ToString());
                }

                if (!auditInfo.isFieldSet("time"))
                {
                    auditInfo.put("time", DateTime.Now);
                }
            }
            else
            {
                auditInfo = Application.currentApp.bizObjMgr.create("AuditInfo");
                string id = string.Empty;
                if (map.containsField("id"))
                {
                    id = map.get("id") as string;
                    if ((id == null) || (((string)id) == string.Empty))
                    {
                        id = Guid.NewGuid().ToString();
                    }
                }

                // Setup audit info project
                auditInfo.put("id", id);
                auditInfo.put("eventId", map.containsField("eventId") ? map.get("eventId") : string.Empty);
                auditInfo.put("time", map.containsField("time") ? map.get("time") : DateTime.Now);
                auditInfo.put("data1", map.containsField("data1") ? map.get("data1") : null);
                auditInfo.put("data2", map.containsField("data2") ? map.get("data2") : null);
            }

            // Used for backward compatibility
            IDictionary info = new Hashtable();
            info["eventId"] = auditInfo.get("eventId");
            info["time"] = auditInfo.get("time");
            info["data1"] = auditInfo.get("data1");
            info["data2"] = auditInfo.get("data2");


            //Required by BaseLog!
            info["message"] = auditInfo;
            info["newLine"] = true;
            info["isStartup"] = false;
            info["level"] = 1;

            // Standard elements
            info["machineName"] = Environment.MachineName;

            IApplication app = Application.currentApp;
            if (app != null)
            {
                if (app.resMgr != null)
                {
                    info["applicationId"] = app.resMgr.resolve("$ApplicationId$");
                    info["applicationName"] = app.resMgr.resolve("$ApplicationName$");
                }

                if (app.securityMgr != null && app.securityMgr.currentPrincipal != null)
                {
                    info["currentUser"] = app.securityMgr.currentPrincipal.userName;
                }
            }

            this.notifyObservers(info);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventId"></param>
        /// <param name="data1"></param>
        /// <param name="data2"></param>
        public void write(string eventId, object data1, object data2)
        {
            IBizObj auditInfo = Application.currentApp.bizObjMgr.create("AuditInfo");
            auditInfo.put("id", Guid.NewGuid().ToString());
            auditInfo.put("eventId", eventId);
            auditInfo.put("time", DateTime.Now);
            auditInfo.put("data1", data1);
            auditInfo.put("data2", data2);

            // Call other impl
            write(auditInfo);
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Overriden to ensure that Audit calls are synchronous.  Audit needs to be guaranteed
        /// delivery.  The observer should ensure this and the notifiyObservers is being overridden
        /// to call the observers directly rather than through a queue.  if Observers can't be called
        /// the issue has to bubble up to the calling application.
        /// </summary>
        /// <param name="info"></param>
        protected override void notifyObservers(IDictionary info)
        {
            lock (m_observers)
            {
                foreach (ICall observer in m_observers)
                {
                    try
                    {
                        if (info != null)
                        {
                            observer.call(info);
                        }
                        else
                        {
                            observer.call();
                        }
                    }
                    catch (Exception e)
                    {
                        throw new AuditException(string.Format("Unable to notify audit observer {0}", observer.Method), e);
                    }
                }
            }
        }

        #endregion
    }

    [Serializable]
    public class AuditException : BaseException
    {
        public AuditException()
            : base()
        {
        }

        public AuditException(string message)
            : base(message)
        {
        }

        public AuditException(string message, Exception innerException)
            : base(message, innerException)
        {
        }

        public AuditException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
        }
    }
}
